// 线程的封装  --- 面向对象封装一个线程

// 防止头文件被重复包含
//  1 . #pragma once
//  2 .  使用 #ifndef、#define 和 #endif 包裹代码
#ifndef _THREAD_HPP_
#define _THREAD_HPP_

#include <iostream>
#include <pthread.h>
#include <string>
#include <cstring>
#include <functional>
#include "common.hpp"

namespace ThreadModel
{

    static uint32_t num = 1; // 静态无符号的全局计数器

    //线程可能处理不同的任务 , 所以用包装器包装一下函数指针
    using func_t = std::function<void()>; 

    class Thread
    {
    private:
        // 线程处理方法 -- 该方法是类的成员函数 , 默认有 this指针 , 所以需要设置为静态成员函数 , 这样没有 this 指针
        static void *Routinue(void *args) // args 要得到该线程的相关信息 , 外部传了 this , this 可以找到一个线程类型
        {
            Thread *Self = static_cast<Thread *>(args); // args 就是 this 传过来的
            Self->IsRunning(); // 进入到这里就开始运行了 !!
            // if (Self->_isdetaching) // 自己分离自己
            //     Self->Detach();

            //int pthread_setname_np(pthread_t thread, const char *name);
            //这个函数是给线程设置一个名字 , 因为默认使用被创建的名ID , 我们自己设置
            pthread_setname_np(Self->_tid , Self->_name.c_str());
            //执行任务
            Self->_task(); //回调函数
            
            return nullptr;
        }

        void IsRunning()
        {
            _isrunning = true;
        }

         void IsDetaching()
        {
            std::cout << "Thread [" << _name << " ] is detaching !" << std::endl;
            _isdetaching = true; // 已经被分离
        }

    public:
        Thread(func_t task)
        : _task(task)
        {
            // 每次调用构造 ++ num
            _name = "thread-" + std::to_string(num++);
        }
        ~Thread() {}

        // 启动线程
        void Start()
        {
            if (_isrunning)
                return; // 已经运行了就退出
            // 创建线程
            int n = pthread_create(&_tid, nullptr, Routinue, this); // 最后一个参数是传的线程的相关信息 , 因为是类的成员函数 , 所以 this 指针就指向该线程,所以传this指针就可以找到该线程的相关信息了
            if (n == 0)
            {
                std::cout << "create : " << _name << " success !" << std::endl;
            }
            else
            {
                std::cerr << "create : " << _name << " fail !" << std::endl;
                ERRORINFOM("pthread_create");
            }
        }

        // 线程分离 -- 可以是在创建线程之前分离 ,
        void Detach()
        {
            if (_isdetaching)
                return; // 已经被分离了 , 就退出
            if (_isrunning)
                pthread_detach(_tid); // 如果线程运行了 , 需要被分离就用函数

            IsDetaching(); // 线程还没有运行 ,需要先分离线程 , 就把线程分离置为真 , 方便后续判断
        }

        // 停止线程
        void Stop()
        {
            // 线程运行了再终止 , 否则啥也不干 !
            if (_isrunning)
            {
                // 终止就是取消这个线程
                int n = pthread_cancel(_tid);
                if (n == 0)
                {
                    _isrunning = false; // 不运行了 !
                    std::cout << "[ " << _name << " ]" << "is cancel !" << std::endl;
                }
                else
                {
                    std::cerr << strerror(n) << std::endl; // 根据错误码打印错误信息
                }
            }
        }

        // 等待线程
        void Join()
        {
            // 这里要注意 , 如果一个线程被分离了 , 就不能等待了 !
            if (_isdetaching)
            {
                std::cout << "[ " << _name << " ]" << "is detaching Join error !" << std::endl;
                return;
            }

            int n = pthread_join(_tid, &_ret);
            if (n == 0)
            {
                std::cout << "join : " << _name << " success !" << std::endl;
            }
            else
            {
                std::cout << "Join [ " << _name << " ] fail !" << std::endl;
            }
        }

    private:
        pthread_t _tid = 0;        // 线程的ID , 给缺省值 , 默认是 0  , 创建由系统分配
        std::string _name;         // 线程的名字 : 如 , thread-1
        void *_ret;                // 线程返回值
        bool _isrunning = false;   // 线程是否运行 , 默认 -- > 否
        bool _isdetaching = false; // 线程是否被分离 , 默认 -- > 否
        func_t _task;
    };

}

#endif